package utils

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/antchfx/xpath"
	htmlquery "github.com/antchfx/xquery/html"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

//连接的配置
type HttpDirectoryConfig struct {
	Url        string //url
	TargetPath string
	PathMap    map[string]string
	FileCount  uint
}

func (m *HttpDirectoryConfig) CreateHttpDirectory(url string, targetPath string) {
	if strings.HasSuffix(url, "/") {
		url = strings.TrimRight(url, "/")
	}
	m.Url = url
	m.TargetPath = targetPath
	m.PathMap = make(map[string]string)
	m.FileCount = 0
}

//针对httpserver启动的文件夹服务
func (m *HttpDirectoryConfig) GetUrlPaths(url string, relativePath string) error {
	//fmt.Printf("%s \n", url) // output href
	if strings.HasSuffix(url, "/") {
		url = strings.TrimRight(url, "/")
	}
	resp, err := http.Get(url)
	if err != nil {
		log.Fatalln("http错误:", err)
	}
	if resp.StatusCode == 200 {
		//fmt.Println("ok")
		doc, err := htmlquery.Parse(resp.Body)
		if err != nil {
			log.Fatalln("解析html错误:", err)
			return err
		}
		// Option 1: using xpath's expr to matches nodes.
		//expr := xpath.MustCompile("count(//div[@class='article'])")
		//fmt.Printf("%f \n", expr.Evaluate(htmlquery.CreateXPathNavigator(doc)).(float64))

		expr := xpath.MustCompile("//a/@href")
		iter := expr.Evaluate(htmlquery.CreateXPathNavigator(doc)).(*xpath.NodeIterator)
		for iter.MoveNext() {
			href := iter.Current().Value()
			if href != "" && href != "\\" && href != "../" && href != "/" && (!strings.HasSuffix(href, "../")) && (!strings.HasSuffix(href, "..\\")) {
				//fmt.Printf("url:%s | href:%s \n", url, href)
				href = strings.ReplaceAll(href, "\\", "/")
				//fmt.Printf("url:%s | href:%s \n", url, href)
				//判断是文件夹
				if strings.HasSuffix(href, "\\") || strings.HasSuffix(href, "/") {
					os.MkdirAll(m.TargetPath+href, 0777)
					if strings.HasPrefix(href, "\\") || strings.HasPrefix(href, "/") {
						if m.PathMap[href] == "" {
							m.PathMap[href] = m.Url + href
							m.GetUrlPaths(m.Url+href, href)
						} else {
							continue
						}
					} else {
						m.GetUrlPaths(url+href, href)
					}
				} else {
					//前缀有 / 是绝对路径
					if strings.HasPrefix(href, "\\") || strings.HasPrefix(href, "/") {
						//fmt.Printf("%s |  %s \n", url+href, m.TargetPath+href) // output href
						m.DownFile(m.Url+href, m.TargetPath+href)
					} else {
						//fmt.Printf("%s |  %s \n", url+href, m.TargetPath+relativePath+href) // output href
						m.DownFile(url+href, m.TargetPath+relativePath+href)
					}
				}
			} else {
				continue
			}
		}
	} else {
		log.Fatalln("http加载返回错误状态吗:", resp.StatusCode)
		return errors.New("http加载返回错误状态吗:" + string(resp.StatusCode))
	}
	return nil
}

//下载http文件
func (m *HttpDirectoryConfig) DownFile(url, targetPath string) (string, error) {
	m.FileCount += 1
	fmt.Printf("开始下载第%d个文件， 下载地址:%s ， 存储位置: %s \n", m.FileCount, url, targetPath)
	res, httpErr := http.Get(url)
	if httpErr != nil {
		return "Http Error", httpErr
	}

	defer res.Body.Close()
	reader := bufio.NewReaderSize(res.Body, 64*1024) // 获得reader对象
	file, createErr := os.Create(targetPath)
	if createErr != nil {
		return "Create Error", createErr
	}

	writer := bufio.NewWriter(file) // 获得writer对象
	_, copyErr := io.Copy(writer, reader)
	if copyErr != nil {
		return "Copy Error", copyErr
	}

	return targetPath, nil
}

//
//// 下载文件夹
//func (ftpSourceManager *HttpDirectoryConfig) DownloadDir(FtpPath, TargetPath string) error {
//	walker := ftpSourceManager.Conn.Walk(FtpPath)
//	for walker.Next() {
//		local := strings.Replace(walker.Path(), FtpPath, TargetPath, 1)
//		if walker.Stat().Type == ftp.EntryTypeFolder {
//			os.MkdirAll(local, 0777)
//		} else {
//			func() error {
//				f, err := os.OpenFile(local, os.O_RDWR|os.O_CREATE, 0777)
//				if err != nil {
//					fmt.Println("Create File error", err)
//					return err
//				}
//				defer f.Close()
//				r, err := ftpSourceManager.Conn.Retr(walker.Path())
//				if err != nil {
//					fmt.Println("Get Ftp File error", err)
//					return err
//				}
//				defer r.Close()
//				io.Copy(f, r)
//				return nil
//			}()
//		}
//	}
//	return nil
//}
